package tool

import cats.data.Validated
import implicits.Implicits._
import org.apache.commons.lang3.StringUtils
import play.api.libs.json.Json
import shared.VarTool
import tool.Pojo.SampleInfoFileCheckData

/**
 * Created by yz on 12/3/2020
 */

class SampleInfoFileValidTool(lines: List[List[String]]) {

  val headers = lines.head.map(_.toLowerCase)
  val fileInfo = "样品信息文件"
  val hasHeaders = List("index号", "样品编号", "项目", "性别", "类型", "板号", "panel")

  def validHeadersRepeat = {
    val repeatHeaders = headers.diff(headers.distinct)
    val valid = repeatHeaders.isEmpty
    Validated.cond(valid, true, s"${fileInfo}表头 ${repeatHeaders.head} 重复!")
  }

  def validHeadersExist = {
    val noExistHeaders = hasHeaders.diff(headers)
    val valid = noExistHeaders.isEmpty
    Validated.cond(valid, true, s"${fileInfo}表头 ${noExistHeaders.head} 不存在!")
  }

  def validColumnNum = {
    val info = lines.drop(1).zipWithIndex.map { case (tmpColumns, i) =>
      val columns = tmpColumns
      val inValid = columns.size <= headers.size
      val inMessage = if (!inValid) {
        s"${fileInfo}第${i + 2}行列数不正确,存在多余列!"
      } else ""
      (inValid, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2).notEmptyLines
    Validated.cond(valid, true, messages.head)
  }

  def validNonEmpty = {
    val emptyColumns = List("index号", "样品编号", "板号", "panel")
    val info = lines.drop(1).zipWithIndex.map { case (columns, i) =>
      val lineMap = headers.zip(columns).toMap
      val op = columns.filter { column =>
        val j = columns.indexOf(column)
        val header = headers(j)
        emptyColumns.contains(header)
      }.filter { column =>
        StringUtils.isEmpty(column)
      }.headOption
      val inMessage = if (op.nonEmpty) {
        val j = columns.indexOf(op.get)
        s"${fileInfo}第${i + 2}行第${j + 1}列为空!"
      } else ""
      (op.isEmpty, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2)
    Validated.cond(valid, true, messages.head)
  }

  def validFactorColumn = {
    val factorMap = Map("性别" -> List("男", "女", ""),
      "类型" -> VarTool.kindStrs,
      "panel" -> VarTool.kitNames
    )

    val columns = factorMap.keySet
    val info = columns.map { header =>
      val totalColumns = lines.selectOneColumn(header)
      val op = totalColumns.filter { column =>
        !factorMap(header).contains(column)
      }.headOption
      val inValid = op.isEmpty
      val inMessage = if (!inValid) {
        val value = op.get
        val j = headers.indexOf(header)
        val i = totalColumns.lastIndexOf(value)
        s"${fileInfo}第${i + 2}行第${j + 1}列只能为(${factorMap(header).mkString("、")})中的一个!"
      } else ""
      (inValid, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.filter(x => !x._1).map(_._2)
    Validated.cond(valid, true, messages.head)
  }

  def validColumnsRepeat = {
    val repeatColumns = List(VarTool.indexStr, VarTool.idStr)
    val info = repeatColumns.map { header =>
      val totalColumns = lines.selectOneColumn(header)
      val repeatValues = totalColumns.diff(totalColumns.distinct)
      val inValid = repeatValues.isEmpty
      val inMessage = if (!inValid) {
        val repeatValue = repeatValues.head
        val j = headers.indexOf(header)
        val i = totalColumns.lastIndexOf(repeatValue)
        s"${fileInfo}第${i + 2}行第${j + 1}列重复!"
      } else ""
      (inValid, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2)
    Validated.cond(valid, true, messages.head)
  }

  def validIdExist(data: SampleInfoFileCheckData) = {
    val totalColumns = lines.selectOneColumn(VarTool.idStr)
    val dbIds = data.dbIds
    val existIds = totalColumns.filter(dbIds.contains(_))
    val valid = if (data.isCover.isDefined) true else existIds.isEmpty
    val message = if (valid) {
      ""
    } else {
      val message = if (existIds.size > 5) {
        s"有${existIds.size}个样本在数据库中已存在，确定覆盖？<br>样本详情如下：<br>${existIds.mkString("、")}"
      } else {
        s"样品编号（${existIds.mkString("、")}）在数据库中已存在，确定覆盖？"
      }
      val json = Json.obj("confirm" -> true, "message" -> message)
      Json.stringify(json)
    }
    Validated.cond(valid, true, message)
  }


}

object SampleInfoFileValidTool {

  def valid(lines: List[List[String]], data: SampleInfoFileCheckData) = {
    val fileValidTool = new SampleInfoFileValidTool(lines)
    import fileValidTool._
    validHeadersRepeat.andThen { b =>
      validHeadersExist
    }.andThen { b =>
      validColumnNum
    }.andThen { b =>
      validNonEmpty
    }.andThen { b =>
      validFactorColumn
    }.leftMap { x =>
      s"样本信息表有误，请重新上传!\n${x}"
    }.andThen { b =>
      validIdExist(data)
    }

  }

}
